/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.base.service.impl;

import com.xy.biz.base.domain.bo.DictBO;
import com.xy.biz.base.domain.bo.DictPropertyBO;
import com.xy.biz.base.domain.converter.DictConverter;
import com.xy.biz.base.domain.dto.DictPropertyDTO;
import com.xy.biz.base.domain.query.DictQuery;
import com.xy.biz.base.domain.req.*;
import com.xy.biz.base.domain.resp.ListDictItemResponse;
import com.xy.biz.base.manager.DictManager;
import com.xy.biz.base.service.DictService;
import com.xy.lang.domain.IntegerHolder;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.StringKeyValue;
import com.xy.lang.domain.treeing.TreeItem;
import com.xy.lang.util.CollectionUtilsEx;
import com.xy.tool.concurrent.locks.DisLock;
import com.xy.tool.concurrent.locks.DisLockFactory;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.minio.util.StringUtils;
import com.xy.tool.util.BeanUtilsEx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 *
 *
 * @author zsp
 * @date 2020-5-23
 */
@Service
public class DictServiceImpl implements DictService {

    @Autowired
    private DictManager dictManager;
    @Autowired
    private DisLockFactory disLockFactory;
    @Autowired
    private DictInitializeEventBus dictInitializeEventBus;

    @Override
    public Result<?> saveDict(SaveDictRequest request) {
        Long parentDictId = request.getParentDictId();
        if (!validateParentDictId(parentDictId)) {
            return Result.ofNotFound("父字典不存在");
        }
        DictBO dictBO = DictConverter.toBO(request);
        if (Objects.equals(true, request.isAutoCodeFlag())) {
            dictBO.setDictCode("info");
        }
        if (Objects.equals(true, request.isRepeatFlag())) {
            if (dictManager.isDictExists(0L, dictBO.getDictGroupCode(), dictBO.getDictValue())) {
                return Result.ofConflict("字典值已存在");
            }
        }
        Long tenantId = UserContextHolder.getTenantId();
        dictBO.setTenantId(tenantId);
        String dictGroupCode = dictBO.getDictGroupCode();
        String dictCode = dictBO.getDictCode();
        String dictCodeResource = "dict-" + dictGroupCode + "-" + dictCode + "-" + tenantId;
        DisLock disLock = disLockFactory.create();
        if (disLock.lock(dictCodeResource, 5000L)) {
            try {
                if (dictManager.isDictExists(dictGroupCode, dictCode, tenantId)) {
                    return Result.ofConflict("字典已存在");
                }
                dictBO.setCreateTime(LocalDateTime.now());
                dictBO.setUpdateTime(LocalDateTime.now());
                List<DictPropertyBO> dictPropertyBOList = dictBO.getPropertyList();
                if (!CollectionUtils.isEmpty(dictPropertyBOList)) {
                    int count = 0;
                    if (parentDictId != null) {
                        count = (dictManager.getMaxPropertyKey(parentDictId) / 100) * 100 + 100;
                    }
                    for (DictPropertyBO dictPropertyBO : dictPropertyBOList) {
                        dictPropertyBO.setTenantId(tenantId);
                        dictPropertyBO.setPropertyKey(++count);
                    }
                }
                dictBO = dictManager.saveDict(dictBO);
                if (Objects.nonNull(dictBO)) {
                    dictInitializeEventBus.fireHandler(dictBO.getDictId());
                    if (Objects.equals(true, request.isAutoCodeFlag())) {
                        dictBO.setDictCode(dictBO.getDictId().toString());
                        int affectedRows = dictManager.updateDict(dictBO);
                        if (affectedRows > 0) {
                            return Result.success();
                        }
                    }
                    if (dictBO.getDictId() != 0) {
                        return Result.success();
                    }
                }
            } finally {
                disLock.unlock(dictCodeResource);
            }
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * 更新名字
     *
     * @param request
     */
    @Override
    public Result<?> updateDictName(UpdateDictRequest request) {
        DictBO dictBO = DictConverter.toBO(request);
        dictBO.setUpdateTime(LocalDateTime.now());
        int row = dictManager.updateDictName(dictBO);
        if (row > 0) {
            return Result.success(row);
        }
        return Result.fail();
    }

    @Override
    public Result<?> updateDict(SaveDictRequest request) {
        if (!validateParentDictId(request.getParentDictId())) {
            return Result.ofNotFound("父字典不存在");
        }
        DictBO found = getDict(GetDictRequest.builder()
                .dictId(request.getDictId())
                .withProperty(true)
                .ignorePropertyDeleteFlag(true)
                .build());
        if (null == found) {
            return Result.ofNotFound("未找到字典");
        }
        if (request.getParentDictId() == null) {
            request.setParentDictId(0L);
        } else {
            Long dictId = request.getDictId();
            if (Objects.equals(dictId, request.getParentDictId())) {
                return Result.ofErrorData("设置了错误的上级字典");
            } else {
                Long parentDictId = request.getParentDictId();
                List<Long> childrenDictIdList = dictManager.listChildrenDictId(dictId);
                if (!CollectionUtils.isEmpty(childrenDictIdList)
                        && childrenDictIdList.stream().anyMatch(e -> Objects.equals(parentDictId, e))) {
                    return Result.ofErrorData("设置了错误的上级字典");
                }
            }
        }
        Long tenantId = found.getTenantId();
        found.setDictValue(request.getDictValue());
        found.setMemo(request.getMemo());
        found.setParentDictId(request.getParentDictId());
        found.setSequence(request.getSequence());
        found.setUpdateTime(LocalDateTime.now());
        List<DictPropertyBO> dictPropertyBOList = found.getPropertyList();
        dictPropertyBOList = dictPropertyBOList == null ? new ArrayList<>() : dictPropertyBOList;
        IntegerHolder count = new IntegerHolder(dictPropertyBOList.size());
        List<List<DictPropertyBO>> allList = CollectionUtilsEx.fork(dictPropertyBOList,
                BeanUtilsEx.copyPropertiesForNewList(request.getPropertyList(), () -> new DictPropertyBO()),
                DictPropertyBO::getPropertyName,
                (sourceItem, targetItem) -> {
                    targetItem.setDictPropertyId(sourceItem.getDictPropertyId());
                },
                (addItem) -> {
                    addItem.setDictId(found.getDictId());
                    addItem.setTenantId(tenantId);
                    addItem.setPropertyKey(count.increment(1));
                });
        found.setIntersectionList(allList.get(0));
        found.setAddList(allList.get(1));
        found.setSubtractList(allList.get(2));
        int affectedRows = dictManager.updateDict(found);
        if (affectedRows > 0) {
            dictInitializeEventBus.fireHandler((long) affectedRows);
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private boolean validateParentDictId(Long parentDictId) {
        if (null != parentDictId && parentDictId != 0L && !dictManager.isDictExists(parentDictId)) {
            return false;
        }
        return true;
    }

    @Override
    public Result<?> deleteDict(Long dictId) {
        if (dictManager.isDictHasChildren(dictId)) {
            return Result.ofErrorStatus("字典下已存在子字典项，请先删除子字典项");
        }
        int affectedRows = dictManager.deleteDict(dictId);
        if (affectedRows > 0) {
            dictInitializeEventBus.fireHandler((long) affectedRows);
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteDictNoVerify(Long dictId) {
        int affectedRows = dictManager.deleteDict(dictId);
        if (affectedRows > 0) {
            dictInitializeEventBus.fireHandler((long) affectedRows);
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public DictBO getDict(GetDictRequest request) {
        return dictManager.getDict(request);
    }

    @Override
    public ListDictItemResponse getDictItem(GetDictByCodeRequest request) {
        return dictManager.getDictItem(request);
    }

    @Override
    public List<DictBO> listDict(DictQuery query) {
        return dictManager.listDict(query);
    }

    @Override
    public int countDict(DictQuery query) {
        return dictManager.countDict(query);
    }

    @Override
    public List<ListDictItemResponse> listDictItem(ListDictItemRequest request) {
        return dictManager.listDictItem(request);
    }

    @Override
    public List<StringKeyValue> listDictGroupItem(Integer type) {
        return dictManager.listDictGroupItem(type);
    }

    @Override
    public List<TreeItem> listDictGroupItemAll(Integer type) {
        return dictManager.listDictGroupItemAll(type);
    }

    /**
     * 根据分组code拿到所有数据
     * @param request
     * @return
     */
    @Override
    public List<TreeItem> listDictGroupItemByGroupCode(ListDictItemRequest request) {
        return dictManager.listDictGroupItemByGroupCode(request);
    }

    @Override
    public Result<?> updateAll(UpdateDictAllRequest request) {
        Integer affectedRows = dictManager.updateAll(request);
        return Result.success(affectedRows);
    }

    @Override
    public List<DictPropertyDTO> listDictProperty(GetDictRequest request) {
        return dictManager.listDictProperty(request);
    }

    @Override
    public List<DictPropertyDTO> listDictProperties(GetDictRequest request) {
        return dictManager.listDictProperties(request);
    }

}
